﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkETL.SaveBatchedChanges;

namespace EntityFrameworkETL
{
    public class BatchCommands
    {
        /// <summary>
        /// Batch commands staying within sql limit of 2100 parameters
        /// </summary>
        /// <param name="constructor"></param>
        /// <param name="commands"></param>
        public IEnumerable<BatchedCommand> Execute(IEnumerable<DbCommandCacheItem> commands)
        {
            var result = new List<BatchedCommand>();
            var sql = new System.Text.StringBuilder();
            var parameters = new List<DbParameter>();
            var batchedCommands = new List<DbCommandCacheItem>();
            foreach (DbCommandCacheItem command in commands)
            {
                if ((parameters.Count + command.DbCommand.Parameters.Count) > 2000)
                {
                    //Execute and clear
                    result.Add(new BatchedCommand(sql.ToString(), parameters.ToArray(), batchedCommands));
                    parameters.Clear();
                    sql.Clear();
                }

                var commandSql = command.DbCommand.CommandText;
                List<DbParameter> commandParameters = new List<DbParameter>();
                foreach (DbParameter param in command.DbCommand.Parameters)
                {
                    commandParameters.Add(param);
                }
                foreach (DbParameter param in commandParameters)
                {
                    //fix parameter names
                    var nextParameterName = "@p" + parameters.Count.ToString();
                    commandSql = commandSql.Replace("(" + param.ParameterName, "(" + nextParameterName);
                    commandSql = commandSql.Replace(param.ParameterName + ",", nextParameterName + ",");
                    commandSql = commandSql.Replace(param.ParameterName + ")", nextParameterName + ")");
                    param.ParameterName = nextParameterName;

                    parameters.Add(param);
                    command.DbCommand.Parameters.Remove(param);
                }
                sql.AppendLine(commandSql);
                batchedCommands.Add(command);
            }

            //Execute Batch Query
            result.Add(new BatchedCommand(sql.ToString(), parameters.ToArray(), batchedCommands));
            return result;
        }
    }
}
